package pogvue.analysis;

import java.awt.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
import java.io.*;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import pogvue.datamodel.*;
import pogvue.io.*;
import pogvue.gui.*;
import pogvue.gui.hub.*;
import pogvue.gui.event.*;
import pogvue.analysis.*;
import pogvue.gui.schemes.*;

public class SearchThread extends Thread  {
  AlignmentI align;
  
  Controller controller;
  AlignViewport viewport;
  
  Vector pwms;
  Vector matvect;
  Vector mats      = null;
  Vector fullmats  = null;

  Hashtable names;
  
  Vector out;
  
  ActionListener l;
  
  double threshold;
  double infContent;
  String searchType = "search";
  int    offset = 0;

  String str;

  public SearchThread(String str, int offset, ActionListener l) {
    setActionListener(l);
    this.offset = offset;
    this.str = str;
  }
  public SearchThread(AlignmentI align, Controller controller, AlignViewport viewport) {
      this.align      = align;
	this.controller = controller;
	this.viewport   = viewport;

    }
    public void setViewport(AlignViewport viewport) {
	this.viewport = viewport;
    }
  public void setSearchType(String type) {

    this.searchType = type;
  }
  public String getSearchType() {
      return searchType;
  }
  public void setThreshold(double t) {
    this.threshold = t;
  }
  public void setInfContent(double inf) {
    this.infContent = inf;
  }
    public void setActionListener(ActionListener l) {
	this.l = l;
    }

  public void run() {

    if (str != null) {
      search(str);
    } else {
      searchViewport();
    }

    if (l != null) {
      ActionEvent e = new ActionEvent(this,0,"Done");
      
      l.actionPerformed(e);
    }
  }

  public Vector getOutput() {
    return out;
  }

  public void setNames(String namestr) {
    StringTokenizer str = new StringTokenizer(namestr);
    names = new Hashtable();
    while (str.hasMoreTokens()) {
      names.put(str.nextToken(),new Integer(1));
    }
    
    mats    = null;
    matvect = null;
  }

  public void searchViewport() {

    out = new Vector();

    getTransfacMatrices();
    getSpliceMatrices();

    int start  = viewport.getStartRes();
    int end    = viewport.getEndRes();
    
    if (searchType.equals("Transfac")) {
      search(viewport.getAlignment().getSequenceAt(0).getSequence(start,end));	  
    } else if (searchType.equals("Splices")){
      search(viewport.getAlignment().getSequenceAt(0).getSequence(start,end));	  
    }

  }

  public void search(String str) {

    getTransfacMatrices();
    getSpliceMatrices();

    out = searchMatrices(str,matvect);
    
  }



  public Vector  searchMatrices(String str, Vector pwms) {
  
    out = new Vector();

    Vector matches = new Vector();

    for (int j = 0; j < pwms.size(); j++) {
      String    name     = ((TFMatrix)mats.elementAt(j)).getName();
      Pwm       pwm      = (Pwm)pwms.elementAt(j);
      double [] pwmarray = pwm.getPwm();
      int       len      = pwmarray.length/4;
      
      System.out.println("Searching " + name);
      int i = 0;

      while (i < (str.length() - len)) {

	String sub    = str.substring(i,i+len);
	String revsub = ResidueProperties.reverseComplement(sub);

	double[] seqvec = Correlation4.seqvec(new Sequence(sub,sub,1,sub.length()));	      
	double[] revvec = Correlation4.seqvec(new Sequence(revsub,revsub,1,revsub.length()));	      

	Pwm      tmppwm1  = new Pwm(seqvec,"");
	Pwm      tmppwm2  = new Pwm(revvec,"");
	
	PwmCluster pwmclus1 = new PwmCluster(tmppwm1);
	PwmCluster pwmclus2 = new PwmCluster(tmppwm2);
	      
	double forcorr = pwm.scoreLogOdds(seqvec);
	double revcorr = pwm.scoreLogOdds(revvec);

	if (forcorr > threshold) {

	  TFMatch match = new TFMatch((TFMatrix)mats.elementAt(j),pwm.getConsensus(),sub,forcorr,1);

	  matches.addElement(match);
		  
	  SequenceFeature sf = new SequenceFeature(null,"Transfac",i+offset,i+len+offset,"");
	  sf.setId(name);
	  sf.setScore(forcorr);
	  out.addElement(sf);
	
	}

	if (revcorr > threshold) {

	  TFMatch match = new TFMatch((TFMatrix)mats.elementAt(j),pwm.getConsensus(),revsub,revcorr,-1);

	  matches.addElement(match);

	  SequenceFeature sf = new SequenceFeature(null,"Transfac",i+offset,i+len+offset,"");
	  sf.setId(name);
      
	  sf.setScore(revcorr);
	  sf.setStrand(-1);

	  out.addElement(sf);	  
	  
	}
	i++;
      }
    }

    Collections.sort(matches,new ScoreComparer());
    Collections.sort(out,new SeqFeatureScoreComparer());

    int end = 20;

    if (end > matches.size()) {
      end = matches.size();
    }
    for (int i = 0; i < end; i++) {
      TFMatch match = (TFMatch)matches.elementAt(i);
      SequenceFeature sf  = (SequenceFeature)out.elementAt(i);
      match.print();
      System.out.println("Coord is " + sf.getStart() + "\n");
    }
    return out;
  }


  public Vector getTransfacMatrices() {
    if (fullmats == null && viewport != null) {
	fullmats = viewport.getTransfacMatrices();
    }

    if (mats == null) {
      mats    = new Vector();
      matvect = new Vector();

      if (names == null) {
	  for (int i = 0; i < fullmats.size(); i++) {
	      TFMatrix tfm = (TFMatrix)fullmats.elementAt(i);
	      if (tfm.getPwm().getInfContent() > 11) {
		  matvect.addElement(tfm.getPwm());
		  mats.addElement(tfm);
	      }
	      
	  }
      } else {
	  for (int i = 0; i < fullmats.size(); i++) {
	      TFMatrix tfm = (TFMatrix)fullmats.elementAt(i);

	      Enumeration en = names.keys();
	      while (en.hasMoreElements()) {
		  String name = (String)en.nextElement();
		  if (tfm.getName().indexOf(name) >=0) {
		      matvect.addElement(tfm.getPwm());
		      mats.addElement(tfm);
		  }
	      }
	  }
      }
	      
	
    } 
    return mats;
    
  }

  public Vector getSpliceMatrices() {

    if (pwms == null) {
      try {
	Pwm2File pwmfile = new Pwm2File("data/SpliceMotifs.txt","File");
	
	pwms = pwmfile.getPwm();
      } catch (IOException e) {
	System.out.println("Can't read Splice File");
      }
    }
    return pwms;
  }


}